package cn.bo.cloud.common.core.exception;

import org.springframework.core.NestedExceptionUtils;

/**
 * @ClassName CommonRuntimeException
 * @Description Copy from  NestedRuntimeException
 * Handy class for wrapping runtime {@code Exceptions} with a root cause.
 *
 * <p>This class is {@code abstract} to force the programmer to extend
 * the class. {@code getMessage} will include nested exception
 * information; {@code printStackTrace} and other like methods will
 * delegate to the wrapped exception, if any.
 *
 * <p>The similarity between this class and the {@link CommonCheckedException}
 * class is unavoidable, as Java forces these two classes to have different
 * superclasses (ah, the inflexibility of concrete inheritance!).
 *
 * @Author jb.zhou
 * @Date 2020/2/28
 * @Version 1.0
 * @see #getMessage
 * @see CommonCheckedException

 */
public abstract class CommonRuntimeException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    static {
        // 在调用 getMessage() 时，快速加载 CommonExceptionUtils 类以避免 OSGi 上的类加载器死锁问题。
        // 缺陷来源：SPR-5607.
        NestedExceptionUtils.class.getName();
    }

    private Integer code;

    public CommonRuntimeException() {
        super();
    }

    public CommonRuntimeException(String msg) {
        super(msg);
    }

    public CommonRuntimeException(Throwable cause) {
        super(cause);
    }

    public CommonRuntimeException(Integer code, String msg) {
        super(msg);
        this.code = code;
    }

    public CommonRuntimeException(String msg, Throwable cause) {
        super(msg, cause);
    }

    public CommonRuntimeException(Integer code, String msg, Throwable cause) {
        super(msg, cause);
        this.code = code;
    }


    /**
     * 返回详细消息，包括来自嵌套异常的消息（如果有的话）。
     */
    @Override
    public String getMessage() {
        return NestedExceptionUtils.buildMessage(super.getMessage(), getCause());
    }


    /**
     * 检索此异常的最根本原因（如果有的话）。
     */
    public Throwable getRootCause() {
        Throwable rootCause = null;
        Throwable cause = getCause();
        while (cause != null && cause != rootCause) {
            rootCause = cause;
            cause = cause.getCause();
        }
        return rootCause;
    }

    /**
     * 检索此异常的最具体原因，即最内在的原因（根本原因）或此异常本身。
     * <p>与 {@link #getRootCause()} 的不同之处在于，如果没有rootCause，则返回当前异常。
     */
    public Throwable getMostSpecificCause() {
        Throwable rootCause = getRootCause();
        return (rootCause != null ? rootCause : this);
    }

    /**
     * 检查此异常是否包含给定类型的异常: 要么属于给定的类本身，要么包含给定类型的嵌套
     * @param exType 要检查的异常类型
     * @return
     */
    public boolean contains(Class<?> exType) {
        if (exType == null) {
            return false;
        }
        if (exType.isInstance(this)) {
            return true;
        }
        Throwable cause = getCause();
        if (cause == this) {
            return false;
        }
        if (cause instanceof CommonRuntimeException) {
            return ((CommonRuntimeException) cause).contains(exType);
        }
        else {
            while (cause != null) {
                if (exType.isInstance(cause)) {
                    return true;
                }
                if (cause.getCause() == cause) {
                    break;
                }
                cause = cause.getCause();
            }
            return false;
        }
    }

    public Integer getCode() {
        return code;
    }

    public CommonRuntimeException setCode(Integer code) {
        this.code = code;
        return this;
    }
}
